﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;

namespace LCSFlashCards
{
    [Serializable()]
    public class Compartment<T> : IEnumerable<Deck<T>>, ISerializable
    {
        public event EventHandler<CompartmentFinishedEventArgs> CompartmentFinished;
        internal List<Card<T>> tempCards = new List<Card<T>>();
        public int CompartmentNumber { get; private set; }
        public int NumberOfDecks
        {
            get
            {
                return decks.Count;
            }
        }
        private List<Deck<T>> decks = new List<Deck<T>>();
        public Deck<T> this[int index]
        {
            get { return decks[index]; }
            set { decks[index] = value; }
        }
        public IEnumerator<Deck<T>> GetEnumerator()
        {
            return decks.GetEnumerator();
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return decks.GetEnumerator();
        }
        public Compartment(int compNumber)
        {
            this.CompartmentNumber = compNumber;
            for (int i = 0; i < Math.Pow(2, compNumber); i++)
            {
                Deck<T> newDeck = new Deck<T> { DeckNumber = i };
                newDeck.DeckFinished += (o, e) =>
                {
                    RearrangeDecks();
                };
                decks.Add(newDeck);
            }
        }
        private void RearrangeDecks()
        {
            for (int i = 0; i < NumberOfDecks - 1; i++)
                decks[i] = decks[i + 1];
            Deck<T> newDeck = new Deck<T> { DeckNumber = NumberOfDecks-1 };
            newDeck.DeckFinished += (o, e) =>
            {
                RearrangeDecks();
            };
            decks[NumberOfDecks - 1] = newDeck;
            if (CompartmentFinished != null)
                CompartmentFinished(this, new CompartmentFinishedEventArgs());
        }
        public Card<T> GetNextCard()
        {
            Card<T> nextCard = decks[0].FetchNextCard();
            if(nextCard != null)
                tempCards.Add(nextCard);
            return nextCard;
        }
        public void AddCard(Card<T> cardToAdd)
        {
            decks[decks.Count - 1].AddCard(cardToAdd);
        }
        public Compartment(SerializationInfo info, StreamingContext context)
        {
            this.tempCards = (List<Card<T>>)info.GetValue("TempCards", typeof(List<Card<T>>));
            this.CompartmentNumber = (int)info.GetValue("CompartmentNumber", typeof(int));
            this.decks = (List<Deck<T>>)info.GetValue("Decks", typeof(List<Deck<T>>));
        }
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("TempCards", tempCards);
            info.AddValue("CompartmentNumber", CompartmentNumber);
            info.AddValue("Decks", decks);
        }

        internal int CountCards()
        {
            int count = 0;
            foreach (Deck<T> d in this.decks)
                count += d.Count();
            return count + tempCards.Count;
        }

        internal int CountTrueCards()
        {
            int count = 0;
            foreach (Deck<T> d in this.decks)
                foreach (Card<T> c in d)
                    if (c.Tag == CardTag.Successful)
                        count++;
            foreach(Card<T> c in tempCards)
                if (c.Tag == CardTag.Successful)
                    count++;

            return count;
        }

        internal int CountFailedCards()
        {
            int count = 0;
            foreach (Deck<T> d in this.decks)
                foreach (Card<T> c in d)
                    if (c.Tag == CardTag.Failed)
                        count++;
            foreach (Card<T> c in tempCards)
                if (c.Tag == CardTag.Failed)
                    count++;
            return count;
        }

        internal int CountFreshCards()
        {
            int count = 0;
            foreach (Deck<T> d in this.decks)
                foreach (Card<T> c in d)
                    if (c.Tag == CardTag.Fresh)
                        count++;
            foreach (Card<T> c in tempCards)
                if (c.Tag == CardTag.Fresh)
                    count++;

            return count;
        }

        internal int CountDelayedCards()
        {
            int count = 0;
            foreach (Deck<T> d in this.decks)
                foreach (Card<T> c in d)
                    if (c.Tag == CardTag.Delayed)
                        count++;
            foreach (Card<T> c in tempCards)
                if (c.Tag == CardTag.Delayed)
                    count++;

            return count;
        }
    }
}
